package cn.harmonyoslearn.navrouter.models;

import cn.harmonyoslearn.navrouter.datas.JsonValue;
import cn.harmonyoslearn.navrouter.datas.NavrouterInfo;
import cn.harmonyoslearn.navrouter.datas.RouterMap;
import cn.harmonyoslearn.navrouter.utils.FileUtil;
import cn.harmonyoslearn.navrouter.utils.LogUtil;
import com.intellij.openapi.project.Project;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 服务模块用于管理各种配置文件的加载与更新，并跟随插件的启动而加载数据，时刻保持数据与文件系统的一致性
 */
public class ServiceModel {
    private static ServiceModel instance;

    public static ServiceModel getInstance() {
        if (instance == null) {
            instance = new ServiceModel();
        }
        return instance;
    }

    private ServiceModel() {
    }


    /**
     * 是否初始化成功
     */
    private Boolean init = false;
    /**
     * 是否初始化了 NavrouterInfo
     */
    private Boolean initNavrouter = false;
    /**
     * 项目根目录路径
     */
    private String basePath;
    /**
     * 项目project
     */
    private Project project;
    /**
     * RouterMap 模块
     */
    private RouterMapModel routerMap;
    /**
     * NavNames 模块
     */
    private NavNamesModel navNames;
    /**
     * 上一次同步的时间戳
     */
    long time = 0;





    /**
     * 初始化模块
     *
     * @param project 项目project
     */
    public void init(Project project) {
        this.init = true;
        this.project = project;
        this.basePath = project.getBasePath();

        // 判断是否已经初始化了RouterMap，即判断 navrouter-info.json 是否存在，如果存在则加载 navrouter-info.json 中的数据
        initNavrouter = FileUtil.isFile(basePath + "/navrouter-info.json");

        // 没有初始化则需要初始化项目后，重新再初始化
        if (!initNavrouter) {
            this.init = false;
            LogUtil.w("ServiceModel.init", "Navrouter还没有初始化，无法初始化ServiceModel模块");
            return;
        }

        NavrouterInfo navrouterInfoMap = NavrouterInfoModel.getNavrouterInfoMap(basePath);

        // 加载RouterModel数据集，根据 build-profile.json5 中的 models 来找到 router_map.json 文件
        this.routerMap = new RouterMapModel(this.basePath);

        // 加载 NavNames 模块
        this.navNames = new NavNamesModel(this.basePath, navrouterInfoMap, routerMap);
        LogUtil.i("ServiceModel.init", "初始化ServiceModel模块成功");

        // 同步数据
        try {
            this.sync();
        } catch (Exception e) {
            LogUtil.e("ServiceModel.init", "同步数据失败，error:" + e.getMessage());
        }
    }

    /**
     * 向配置中新增一个页面信息
     * @param pageName 文件名称
     * @param note 注释信息
     * @param filePath 新增文件的地址
     * @throws Exception 如果 ServiceModel 没有初始化则抛出错误
     */
    public void addPage(String pageName, String note, String filePath) throws Exception {
        this.isInit();
        String routerMapPath = RouterMapModel.modelFilePath2RouterMapPath(filePath);

        this.navNames.addPage(pageName, note, routerMapPath, filePath);
        this.routerMap.addPage(filePath, pageName);

        // 保存文件
        this.saveFile(routerMapPath);


        if (new Date().getTime() - this.time < 10000) {
            this.sync();
        }
    }

    /**
     * 删除一个页面
     * @param pagePath 文件路径
     * @throws Exception 如果 ServiceModel 没有初始化则抛出错误
     */
    public void deletePage(String pagePath) throws Exception {
        this.isInit();

        String routerMapPath = RouterMapModel.modelFilePath2RouterMapPath(pagePath);
        this.navNames.deletePage(pagePath);
        this.routerMap.deletePage(routerMapPath, pagePath);

        this.saveFile(routerMapPath);
    }

    /**
     * 将配置同步到文件中 <br>
     * 1、先检查router_map.json中的页面是否存在，不存在的配置项删除掉<br>
     * 2、检查navNames.json中的页面与router_map.json中的数据是否一致，多删少补<br>
     */
    public void sync() throws Exception {
        isInit();
        LogUtil.i("ServiceModel.sync", "开始同步配置" );
        // 1、先检查router_map.json中的页面是否存在，不存在的配置项删除掉
        Map<String, RouterMap> routerMaps = this.routerMap.getRouterMaps();
        Map<String, String> navNameMap = new HashMap<>();
        this.navNames.getNavNames().forEach(navName -> navNameMap.put(navName.name, navName.note));

        ArrayList<JsonValue> navNameList = new ArrayList<>();

        routerMaps.forEach((k, v) -> {
            ArrayList<JsonValue> jsonValues = v.routerMap.arrayList("routerMap");

            // 遍历 router_map.json 中的 routerMap 的数据
            for (int i = jsonValues.size() - 1; i >= 0; i--) {
                JsonValue value = jsonValues.get(i);
                String filePath = v.modelPath + "/" + value.getString("pageSourceFile");

                // 检查文件是否存在
                if (!FileUtil.isFile(filePath)) {
                    jsonValues.remove(i);
                    continue;
                }

                // 保存到navNames.json中
                JsonValue name = new JsonValue(new HashMap<>());
                name.addString("name", value.getString("name"));


                // 如果有not则使用原有的not
                String note = navNameMap.get(value.getString("name"));
                if (note == null) {
                    note = "";
                }

                name.addString("note", note);
                name.addString("filePath", filePath.replace(this.basePath, ""));
                name.addString("routerMapPath", v.routerMapPath.replace(this.basePath, ""));
                navNameList.add(name);
            }
        });

        // 2、同步 names
        JsonValue navNames = new JsonValue(new HashMap<>());
        navNames.addArrList("names", navNameList);

        // 保存两个数据
        this.routerMap.setRouterMaps(routerMaps);
        this.navNames.setNavNames(navNames);
        this.saveFile();

        this.time = new Date().getTime();
        LogUtil.i("ServiceModel.sync", "同步配置完成");
    }





    /**
     * 更新文件内容
     * @param filePath 文件名称
     * @param modifyChain 修改的调用链，需要修改Json文件中的哪一个值
     * @param content 修改的内容
     */
    public static void updateFileContent(String filePath, String modifyChain, String content) throws Exception {
        if (!FileUtil.isFile(filePath)) {
            throw new Exception("ServiceModel [updateFileContent] 文件不存在");
        }

        // 读取文件内容
        JsonValue value = new JsonValue(FileUtil.readFileContent(filePath));
        value.setValue(modifyChain, content);

        // 保存文件
        FileUtil.write(filePath, value.toJsonString(), true);
    }





    /**
     * 将缓存中的数据保存到文件中
     */
    private void saveFile() {
        saveFile(null);
    }


    /**
     * 将缓存中的数据保存到文件中
     */
    private void saveFile(String routerMapPath) {
        if (routerMapPath != null) {
            this.routerMap.saveFile(routerMapPath);
        } else {
            this.routerMap.saveFile();
        }

        this.navNames.saveFile();
        FileUtil.refreshAndFindFileByPath(this.basePath);
    }

    /**
     * 是否已经初始化模块
     *
     * @throws Exception 没有初始化
     */
    public void isInit() throws Exception {
        if (!this.init) {
            throw new Exception("ServiceModel It hasn't been initialized yet, Please execute the init function");
        }
    }





    //**************************** get set ****************************//

    /**
     * 是否已经初始化了 NavRouter 项目
     * @return Boolean
     */
    public Boolean getInitNavrouter() {
        return initNavrouter;
    }

    public RouterMapModel getRouterMapModel() throws Exception {
        this.isInit();
        return routerMap;
    }

    public NavNamesModel getNavNamesModel() throws Exception {
        this.isInit();
        return navNames;
    }
}
